package com.ibm.cps.sql.expression;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializable;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.ibm.cps.sql.expression.json.ConditionCompositionExpressionDeserializer;
import com.ibm.util.exception.CPSException;

@JsonDeserialize(using = ConditionCompositionExpressionDeserializer.class)
public class ConditionCompositionExpression implements BooleanExpression, RecursiveExpression, JsonSerializable {
	private BooleanExpression condition1;
	private BooleanExpression condition2;
	private Predicate predicate;
	
	public ConditionCompositionExpression() {
		//Only used for serialization
	}

	public ConditionCompositionExpression(BooleanExpression condition1,
			BooleanExpression condition2, Predicate predicate) {
		this.condition1 = condition1;
		this.condition2 = condition2;
		this.predicate = predicate;
	}
	
	@Override
	public String toString() {
		return "{\"ConditionCompositionExpression\":{\"condition1\":\""
				+ condition1 + "\", \"condition2\":\"" + condition2
				+ "\", \"predicate\":\"" + predicate + "\"}}";
	}

	@Override
	public Set<String> collectVariableNames() {
		Set<String> names = new HashSet<>();
		names.addAll(condition1.collectVariableNames());
		names.addAll(condition2.collectVariableNames());
		return names;
	}

	@Override
	public ExpressionNode[] getChildNodes() {
		return new ExpressionNode[]{condition1, condition2};
	}

	@Override
	public boolean evaluate(FieldEvaluator evaluator) throws CPSException {
		boolean left = condition1.evaluate(evaluator);
		boolean right = condition2.evaluate(evaluator);
		switch(predicate){
		case AND:
			return left && right;
		case OR:
			return left || right;
		case XOR:
			return (left && !right) || (!left && right);
		}
		return false;
	}

	public static enum Predicate{
		AND, OR, XOR
	}

	@Override
	public void updateVariableName(String original, String fullQualifiedName) {
		condition1.updateVariableName(original, fullQualifiedName);
		condition2.updateVariableName(original, fullQualifiedName);
	}

	public BooleanExpression getCondition1() {
		return condition1;
	}

	public void setCondition1(BooleanExpression condition1) {
		this.condition1 = condition1;
	}

	public BooleanExpression getCondition2() {
		return condition2;
	}

	public void setCondition2(BooleanExpression condition2) {
		this.condition2 = condition2;
	}

	public Predicate getPredicate() {
		return predicate;
	}

	public void setPredicate(Predicate predicate) {
		this.predicate = predicate;
	}

	@Override
	public void serialize(JsonGenerator jgen, SerializerProvider provider)
			throws IOException, JsonProcessingException {
		jgen.writeStartObject();
		jgen.writeStringField("predicate", predicate.toString());
		jgen.writeStringField("condition1Type", condition1.getClass().getName());
		jgen.writeObjectField("condition1", condition1);
		jgen.writeStringField("condition2Type", condition2.getClass().getName());
		jgen.writeObjectField("condition2", condition2);
		jgen.writeEndObject();
	}

	@Override
	public void serializeWithType(JsonGenerator jgen,
			SerializerProvider provider, TypeSerializer typeSer)
			throws IOException, JsonProcessingException {
	}
	
}
